MacOS 上 Tailscale 与 Mihomo(TUN 模式) 完美(或许是)共存的方式

#前言:两个“虚拟网卡”的战争

我属于这两个软件的老用户了,但是它们喜欢打架,原因很简单:它们都在争夺路由表的控制权

当 Mihomo 开启 Tun 后,Tailscale 的流量会被 Mihomo 劫持。之前在网上看到建议使用 Userspace 模式(即放弃虚拟网卡转而启动一个 Socks5 监听,然后让 Mihomo 把流量转过去)。在 Mac 上,GUI 版本的 Tailscale 是不支持的,于是我卸载了它,禁用系统保护移除了 sudo systemextensionsctl uninstall W5364U7YZB io.tailscale.ipn.macsys.network-extension 再通过 brew 安装了 CLI 版本的 tailscale 体验了下,感觉很差,原因如下:

SSH 无法使用,这是直接阻止我使用的理由,原本想的是:我不提供服务,TUN 模式或许不需要。实际这一点就把我劝回去了。或许是因为是用户态代理,所以不能支持 SSH,这里没有具体研究细节。

遂放弃这个方案我又回到最开始的思路,在看了一下参考配置后有一个大概的新的思路。

#核心思路

在不断尝试中我发现 curl 通常能直接访问,但是 Chrome 不能访问,而它们的区别或许就是这两类:系统代理流量(Chrome/浏览器等遵循系统代理配置的软件)内核直连流量(终端/SSH/CURL)

因此主要需要做这三件事:

  1. 物理层隔离:通过路由表,让 Tailscale 流量不进入 Mihomo 的 TUN 接口
  2. 应用层直连:通过 macOS 系统设置,让浏览器访问内网时不走代理,即“忽略这些主机与域的代理设置”
  3. 兜底策略:如果流量还是进入了 Mihomo,让 Mihomo 把流量发回 Tailscale 去

#步骤一:Mihomo 配置修改

#1. 固定 Tun 接口并排除路由

Mihomo 默认随机占用 utun,这需要固定下来,并显式排出 Tailscale 网段。在 config.yamltun 字段中:

tun:
  enable: true
  stack: system
  device: utun233           # 关键:固定网卡名,防止和 Tailscale 抢低号段,这将降低后续更新配置的概率
  auto-route: true
  auto-detect-interface: true # 保持开启,否则无法上网
  
  # 关键:告诉内核,这部分流量直接走 Tailscale,别进 Mihomo
  inet4-route-exclude-address:
    - 100.64.0.0/10
  inet6-route-exclude-address:
    - fd7a:115c:a1e0::/48   # 根据你的 Tailscale IPv6 修改

#2. 处理 DNS 问题(可选)

为了让 Chrome 能正确解析内网域名,而不是返回 Fake-IP, 需要修改 dns 配置

dns:
  enable: true
  enhanced-mode: fake-ip
  fake-ip-filter:
    - '+.ts.net'
    - '+.tailscale.com'
    - '+.你的内网域名.dev' # 如果有的话

#3. 接口绑定

这是让流量回到 Tailscale 的关键,如果 Chrome 依然把流量发给了 Mihomo,Mihomo 默认会走物理网卡(en0)导致不通。我们需要将这些流量转入 Tailscale 的网卡。

先在终端运行 ifconfig 确认 Tailscale 的网卡名(通常是 utun6utun3 等)

proxies 中添加一个专用节点:

proxies:
  - name: "tailscale-iface"
    type: direct
    interface-name: utun6   # <--- 必须填写真实的 Tailscale 接口名

添加 proxy-group

proxy-groups:
  - name: Tailscale
    type: select
    proxies:
      - "tailscale-iface"
      - DIRECT

rules 顶部添加强制规则

rules:
  # 必须放在最前面 
  - IP-CIDR,100.64.0.0/10,Tailscale,no-resolve 
  - DOMAIN-SUFFIX,ts.net,Tailscale

添加完成后,重载配置理论便可访问了

#步骤二:macOS 配置代理忽略(可选,如果不想走步骤一)

解决方法:

  1. 打开 系统设置 -> 网络 -> 代理

  2. 找到 “忽略这些主机与域名的代理设置”

  3. 添加如下内容:

100.64.0.0/10, ts.net, *.yourdomain

#总结

这一套方案比 Socks5 模式更好,通过 route-exclude 排出内核路由,配合 interface-name 搞定误入的流量。唯一的缺点就是 macOS 重启后 utun 顺序可能变。这也是为什么要固定 mihomo 的 utun 名,通常 mihomo 和 tailscale 都是开机自启,如果不固定一个就可以变成两者交替使用一个网卡名称进而导致时不时 Tailscale 的内容无法访问

路由表如下:

$/ netstat -nr

Destination        Gateway            Flags           Netif Expire
default            10.1.2.1           UGScg             en0       # 默认物理网卡出口
default            link#23            UCSIg           utun6       # Tailscale 默认路由

# --- Mihomo 接管了大部分公网流量 (utun233) ---
1                  198.18.0.1         UGSc          utun233
2/7                198.18.0.1         UGSc          utun233
4/6                198.18.0.1         UGSc          utun233
... (中间省略部分切片路由) ...

# --- Tailscale 网段的三明治结构 ---

# 1. [Mihomo] 接管 100.0.0.0/10 (前段)
100/10             198.18.0.1         UGSc          utun233

# 2. [Tailscale] 独占 100.64.0.0/10 (核心内网段)
#    这就是 exclude 配置生效的证明,流量被精确分流到了 utun6
100.64/10          link#23            UCS             utun6

# 3. [Mihomo] 接管 100.128.0.0/9 (后段)
100.128/9          198.18.0.1         UGSc          utun233

# ----------------------------------------------

# 其他局域网流量,走物理网卡
10.1.2/24          link#11            UCS               en0
127.0.0.1          127.0.0.1          UH                lo0
198.18.0.1         198.18.0.1         UH            utun233       # Mihomo Fake-IP 网关
2110 Words